package com.mkvld.appietijdenv2.cloud;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.mkvld.appietijdenv2.data.Preferences;
import com.mkvld.appietijdenv2.data.Shift;
import com.mkvld.appietijdenv2.databases.ShiftDatabase;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.provider.Settings.Secure;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

public class CloudV9 {
	public static final String TAG = "CloudSync";
	
	/**
	 * This function sends all google accounts to the server and checks if any of them
	 * has cloud sync enabled
	 * @param context
	 */
	public static void checkCloudSyncEnabled(final Context context) {
		AccountManager accountManager = AccountManager.get(context);
		Account[] accounts = accountManager.getAccountsByType("com.google");
		String[] accountNames = new String[accounts.length];
		for (int i = 0; i < accounts.length; i++) {
			accountNames[i] = accounts[i].name;
		}
		final LocalBroadcastManager manager = LocalBroadcastManager.getInstance(context);
		new AsyncTask<String, Void, String>() {

			@Override
			protected String doInBackground(String... params) {
				HttpClient httpCcient = new DefaultHttpClient();
				HttpPost httpPost = new HttpPost("http://at.remcomokveld.nl/gcm.account.php");
				try {
					List<NameValuePair> content = new ArrayList<NameValuePair>(2);
					for (int i = 0; i < params.length; i++) {
						content.add(new BasicNameValuePair("email" + i, params[i]));
					}
					httpPost.setEntity(new UrlEncodedFormEntity(content));
					
					HttpResponse response = httpCcient.execute(httpPost);

					if (response.getStatusLine().getStatusCode() == 200) {
						 return convertStreamToString(response.getEntity().getContent());
					} 
				} catch (Exception e) {
					Log.e(TAG, e.getLocalizedMessage());
				}
				
				return "";
			}
			
			protected void onPostExecute(String result) {
				if (result.length() > 0) {
					Intent i = new Intent("enableSync");
					i.putExtra("account", result);
					manager.sendBroadcast(i);
				}
			};
			
		}.execute(accountNames);
	}
	
	private static String convertStreamToString(InputStream is) {
        /*
         * To convert the InputStream to String we use the BufferedReader.readLine()
         * method. We iterate until the BufferedReader return null which means
         * there's no more data to read. Each line will appended to a StringBuilder
         * and returned as String.
         */
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
 
        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
	
	
	public static void enableCloudSync(final Context context, String accountName) {
		new AsyncTask<String, Integer, Integer>() {

			@Override
			protected Integer doInBackground(String... params) {
				HttpClient httpCcient = new DefaultHttpClient();
				HttpPost httpPost = new HttpPost("http://at.remcomokveld.nl/sync.enable.php");
				try {
					List<NameValuePair> content = new ArrayList<NameValuePair>(2);
					content.add(new BasicNameValuePair("email", params[0]));
					content.add(new BasicNameValuePair("deviceId", params[1]));
					httpPost.setEntity(new UrlEncodedFormEntity(content));
					
					HttpResponse response = httpCcient.execute(httpPost);
					if (response.getStatusLine().getStatusCode() == 200) {
						  JSONObject responseJSON = new JSONObject(convertStreamToString(response.getEntity().getContent()));
						  Preferences.setCloudId(context, responseJSON.getInt("user_id"));
						  if (responseJSON.getString("action_required").equals("push_data")) {
							  Log.v(TAG, "Push cloud data");
							  pushCloudData(context);
						  } else if (responseJSON.getString("action_required").equals("request_data")) {
							  Log.v(TAG, "Pull cloud data");
							  if (pullCloudData(context, responseJSON.getInt("user_id"))) {
							  }
						  }
						  return 0;
					}
					
				} catch (Exception e) {
					Log.e(TAG, e.getLocalizedMessage());
				}
				return null;
			}			
			@Override
			protected void onPostExecute(Integer result) {
				if (result != null) {
				}
			}
		}.execute(accountName, Secure.getString(context.getContentResolver(), Secure.ANDROID_ID));
	}
	
	public static void disableCloudSync(Context context) {
		new AsyncTask<String, Void, Void>() {
			@Override
			protected Void doInBackground(String... params) {
				try {
					HttpClient httpClient = new DefaultHttpClient();
					HttpPost httpPost = new HttpPost("http://at.remcomokveld.nl/sync.disable.php");
					
					List<NameValuePair> postData = new ArrayList<NameValuePair>(1);
					postData.add(new BasicNameValuePair("device_id", params[0]));
					
					httpPost.setEntity(new UrlEncodedFormEntity(postData));
					
					HttpResponse response = httpClient.execute(httpPost);
					if (response.getStatusLine().getStatusCode() == 204) {
						Log.v(TAG, "Sync disabled");
					} else {
						Log.e(TAG, "Sync not disabled");
					}
				} catch (Exception e) {
					Log.e(TAG, "disableCloudSync failed with reason: " + e.getLocalizedMessage());
				} 
				return null;
			}
		}.execute(Secure.getString(context.getContentResolver(), Secure.ANDROID_ID));
	}
	
	public static void addCloudShift(Context context, Shift shift) {
		new AsyncTask<Object, Void, Boolean>() {
			@Override
			protected Boolean doInBackground(Object... params) {
				try {
					Shift shift = (Shift) params[0];
					String origin = (String) params[1];
					HttpClient httpClient = new DefaultHttpClient();
					HttpPost httpPost = new HttpPost("http://at.remcomokveld.nl/sync.php");
					List<NameValuePair> postData = new ArrayList<NameValuePair>(2);
					
					postData.add(new BasicNameValuePair("type", "add"));
					postData.add(new BasicNameValuePair("origin", origin));
					postData.add(new BasicNameValuePair("year", Integer.toString(shift.getYear())));
					postData.add(new BasicNameValuePair("week", Integer.toString(shift.getWeek())));
					postData.add(new BasicNameValuePair("day", Integer.toString(shift.getDay())));
					postData.add(new BasicNameValuePair("start", Double.toString(shift.getStart())));
					postData.add(new BasicNameValuePair("end", Double.toString(shift.getEnd())));
					
					httpPost.setEntity(new UrlEncodedFormEntity(postData));
					
					HttpResponse response = httpClient.execute(httpPost);
					if (response.getStatusLine().getStatusCode() == 201) {
						return true;
					}
				} catch (Exception e) {
					Log.e(TAG, "addCloudShift failed with reason: "+e.getLocalizedMessage());
				}
				return false;
			}
			
		}.execute(shift, Secure.getString(context.getContentResolver(), Secure.ANDROID_ID));
		
	}

	/**
	 * This method should always be called on an Async Thread
	 * @param context
	 * @return
	 * @throws JSONException
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static boolean pushCloudData(Context context) throws JSONException, ClientProtocolException, IOException {
		JSONObject data = new JSONObject();
		data.put("loan", Preferences.getLoan(context));
		data.put("contract", Preferences.getContract(context));
		data.put("user_id", Preferences.getCloudId(context));
		data.put("push", Preferences.getPushEnabled(context) ? 1 : 0);
		JSONArray shifts = new JSONArray();
		
		for (Shift shift : ShiftDatabase.db.getShifts()) {
			JSONObject jsonShift = new JSONObject();
			jsonShift.put("year", shift.getYear());
			jsonShift.put("week", shift.getWeek());
			jsonShift.put("day", shift.getDay());
			jsonShift.put("start", shift.getStart());
			jsonShift.put("end", shift.getEnd());
			shifts.put(jsonShift);
		}
		
		data.put("shifts", shifts);
		
		HttpClient httpClient = new DefaultHttpClient();
		HttpPost httpPost = new HttpPost("http://at.remcomokveld.nl/sync.init.php");
		
		List<NameValuePair> postData = new ArrayList<NameValuePair>(1);
		postData.add(new BasicNameValuePair("data", data.toString()));
		
		httpPost.setEntity(new UrlEncodedFormEntity(postData));
		
		HttpResponse response = httpClient.execute(httpPost);
		if (response.getStatusLine().getStatusCode() == 201) {
			Log.v(TAG, "data pushed succesfully");
			return true;
		} else {
			Log.e(TAG, "Error while pushing data");
			return false;
		}
	}
	
	public static boolean pullCloudData(Context context, int userId) throws ClientProtocolException, IOException, JSONException {
		HttpClient client = new DefaultHttpClient();
		HttpPost post = new HttpPost("http://at.remcomokveld.nl/sync.init.php");
		
		List<NameValuePair> postData = new ArrayList<NameValuePair>(1);
		postData.add(new BasicNameValuePair("user_id", Integer.toString(userId)));
		post.setEntity(new UrlEncodedFormEntity(postData));
		HttpResponse response = client.execute(post);
		if (response.getStatusLine().getStatusCode() == 200) {
			Log.v(TAG, "Data pull succesfull");
			JSONObject responseJSON = new JSONObject(convertStreamToString(response.getEntity().getContent()));
			Log.v(TAG, responseJSON.toString());
			Preferences.setContract(context, responseJSON.getInt("contract"));
			Preferences.setLoan(context, responseJSON.getDouble("loan"));
			Preferences.setPush(context, responseJSON.getInt("push"));
			JSONArray shiftsJSON = responseJSON.getJSONArray("shifts");
			ShiftDatabase.db.clear();
			for (int i = 0; i < shiftsJSON.length(); i++) {
				JSONObject shiftJSON = shiftsJSON.getJSONObject(i);
				ShiftDatabase.db.addShift(new Shift(shiftJSON.getInt("year"), shiftJSON.getInt("week"), shiftJSON.getInt("day"), shiftJSON.getDouble("start"), shiftJSON.getDouble("end")));
			}
			return true;
		} else {
			Log.v(TAG, "Data pull failed");
			return false;
		}
	}
}